home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 18 / CU Amiga Magazine's Super CD-ROM 18 (1997)(EMAP Images)(GB)[!][issue 1998-01].iso / CUCD / Online / hsc / source / ugly / expstr.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-02  |  26.0 KB  |  1,031 lines

  1. /*
  2.  * This source code is part of hsc, a html-preprocessor,
  3.  * Copyright (C) 1993-1997  Thomas Aglassinger
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  */
  20. /*
  21.  * ugly/expstr.c
  22.  *
  23.  * ugly expandable-string functions
  24.  *
  25.  * Copyright (C) 1995,96  Thomas Aglassinger
  26.  *
  27.  * This program is free software; you can redistribute it and/or modify
  28.  * it under the terms of the GNU General Public License as published by
  29.  * the Free Software Foundation; either version 2 of the License, or
  30.  * (at your option) any later version.
  31.  *
  32.  * This program is distributed in the hope that it will be useful,
  33.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  34.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  35.  * GNU General Public License for more details.
  36.  *
  37.  * You should have received a copy of the GNU General Public License
  38.  * along with this program; if not, write to the Free Software
  39.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  40.  *
  41.  * updated: 26-Feb-1997
  42.  * created: 12-Sep-1995
  43.  *
  44.  */
  45.  
  46. /****** ugly.lib/--background-- **********************************************
  47. *
  48. *   PURPOSE
  49. *       It is a known fact, that the programming langage C comes with one of
  50. *       the most useless string concept ever.
  51. *
  52. *       This function library implements a simple concept to use strings
  53. *       which allocate new memory themself if data will not fit in the
  54. *       current anymore.
  55. *
  56. *       All operations work with a internal structure EXPSTR, which is
  57. *       private and must not be accessed by the programmer. For all
  58. *       interessting information, access functions exist. (See estrlen()
  59. *       and estr2str().)
  60. *
  61. *       An interface with standard strings is provided. (See estr2str() and
  62. *       set_estr().)
  63. *
  64. *   EXAMPLE
  65. *
  66. *       A sample session of including and using some of the functions of
  67. *       this collection can be found below:
  68. *
  69. *       #include "ugly/expstr.h"
  70. *       ...
  71. *
  72. *       EXPSTR * sepp = init_estr( 0 );          \* an expandable string *\
  73. *       EXPSTR * hugo = init_estr( 0 );          \* an expandable string *\
  74. *       STRPTR resi = "this is resi";            \* a standard string *\
  75. *       BOOL ok = ((BOOL) (sepp && hugo);        \* result variable *\
  76. *
  77. *       if (ok)
  78. *       {
  79. *           ok &= set_estr( sepp, "sepp" );      \* set data *\
  80. *           ok &= set_estr( hugo, "hugo" );
  81. *
  82. *           ok &= app_estr( sepp, ". ");         \* append data *\
  83. *           ok &= app_estr( hugo, " and ");      
  84. *           ok &= estrcat( hugo, sepp );         \* ("hugo and sepp.") *\
  85. *
  86. *           ok &= clr_estr( sepp );              \* clear sepp *\
  87. *
  88. *           printf( "sepp=%s\nhugo=%s\n",        \* output data *\
  89. *                   estr2str( sepp ), estr2str( hugo ));
  90. *       }
  91. *
  92. *       if (!ok)
  93. *       {
  94. *           printf( "out of resources\n" );
  95. *       }
  96. *
  97. *       del_estr( hugo );                        \* cleanup (in any case) *\
  98. *       del_estr( sepp );
  99. *
  100. *   NOTES
  101. *       Internally, expandable string still contain a zero-character ('\0')
  102. *       at the end of data.
  103. *
  104. *   BUGS
  105. *       Currently, expandable strings can not hold data which contain a
  106. *       zero-character ('\0'). This is because at several locations I have
  107. *       used functions like strcpy() instead of memcpy().
  108. *
  109. *       Currently, strings expand very stupid in a linear way and not
  110. *       exponentially. That means, if a string runs out of memory,
  111. *       it will only increase by a constant size, instead of eg. increase
  112. *       to twice as large as before. Altough this also works, it is quite
  113. *       slow for long strings.
  114. *
  115. ******************************************************************************
  116. */
  117.  
  118. #include <ctype.h>
  119. #include <stdlib.h>
  120. #include <stdio.h>
  121. #include <string.h>
  122.  
  123. #include "utypes.h"
  124. #include "ustring.h"
  125. #include "umemory.h"
  126.  
  127. #define NOEXTERN_UGLY_STRING_H
  128. #include "expstr.h"
  129.  
  130. #if DEBUG_UGLY_EXPSTR
  131. #define D(x) x
  132. #define DEXP "*expstr* "
  133. #else
  134. #define D(x)                    /* nufin */
  135. #endif
  136.  
  137. /* some functions that perform consistency checks and panic if necessary */
  138. static void es_null(STRPTR func, STRPTR file, ULONG line)
  139. {
  140.     fprintf(stderr, "\n##\n## panic: es=NULL in %s()\n##   called from %s (%lu)\n##\n",
  141.             func, file, line);
  142. }
  143.  
  144. static void s_null(STRPTR func, STRPTR file, ULONG line)
  145. {
  146.     fprintf(stderr, "\n##\n## panic: string=NULL in %s()\n##   called from %s (%lu)\n##\n",
  147.             func, file, line);
  148. }
  149.  
  150. /*
  151.  *-------------------------------------
  152.  * set/clear expstr
  153.  *-------------------------------------
  154.  */
  155.  
  156. /*
  157.  * set_estr_mem
  158.  *
  159.  * set new mem for es_data
  160.  *
  161.  * params: es........expstr where to assign the new mem to
  162.  *         new_size..new size for data part
  163.  * result: TRUE if all ok, new mem in es->es_data;
  164.  * errors: return FALSE, leave es->es_data untouched
  165.  *
  166.  */
  167. static BOOL do_set_estr_mem(EXPSTR * es, STRPTR new_data, size_t new_size)
  168. {
  169.     BOOL ok = TRUE;
  170.  
  171.     if (new_data)
  172.     {
  173.  
  174. #if DEBUG_UGLY_EXPSTR == 2
  175.         D(fprintf(stderr, DEXP "set to %lu (%p->%p)\n",
  176.                   new_size, es->es_data, new_data));
  177. #endif
  178.         es->es_size = new_size;
  179.         es->es_data = new_data;
  180.  
  181.     }
  182.     else
  183.         ok = FALSE;
  184.  
  185.     return (ok);
  186. }
  187.  
  188. BOOL ugly_set_estr_mem(EXPSTR * es, size_t new_size)
  189. {
  190.     return (do_set_estr_mem(es, umalloc(new_size), new_size));
  191. }
  192.  
  193. BOOL ugly_dbg_set_estr_mem(EXPSTR * es, size_t new_size, STRPTR file, ULONG line)
  194. {
  195.     BOOL ok = FALSE;
  196.  
  197.     if (!es)
  198.         es_null("set_estr_mem", file, line);
  199.     else
  200.     {
  201.         ok = do_set_estr_mem(es,
  202.                              ugly_malloc_tracking(new_size, file, line),
  203.                              new_size);
  204.     }
  205.  
  206.     return (ok);
  207. }
  208.  
  209. /****** ugly.lib/set_estr() **************************************************
  210. *
  211. *   NAME
  212. *       set_estr -- set new data for an expandable string.
  213. *
  214. *   SYNOPSIS
  215. *       ok = set_estr( string, data )
  216. *
  217. *       BOOL set_estr
  218. *            ( EXPSTR * string, STRPTR data )
  219. *
  220. *   FUNCTION
  221. *       Reset data of an expandable string to an empty string (""). If
  222. *       necessary, the buffer to store the string data will be expanded.
  223. *
  224. *   INPUTS
  225. *       string - string to clear
  226. *       data   - new data to store, represented as a normal zero-terminated
  227. *                C-string
  228. *
  229. *   RESULT
  230. *       ok - TRUE, if string could be updated. If there have not been enough
  231. *            resources available to allocate a new buffer for the new data,
  232. *            it will still contain the old data, and FALSE will be returned.
  233. *
  234. *   EXAMPLE
  235. *       ok = set_estr( sepp, "data for sepp" );
  236. *
  237. *   SEE ALSO
  238. *       app_estr(), estrcpy()
  239. *
  240. ******************************************************************************
  241. */
  242. BOOL ugly_set_estr(EXPSTR * es, CONSTRPTR s)
  243. {
  244.     BOOL ok = FALSE;
  245.     size_t new_len = strlen(s) + 1;
  246.     STRPTR old_data = es->es_data;
  247.  
  248.     if ((es->es_size == es->es_step)
  249.         && (es->es_size > new_len))
  250.     {
  251.         strcpy(es->es_data, s); /* copy new data */
  252.         es->es_len = new_len;   /* set new len */
  253.         ok = TRUE;
  254.     }
  255.     else if (set_estr_mem(es, modadj(new_len, es->es_step)))
  256.     {
  257.  
  258.         strcpy(es->es_data, s); /* copy new & release old data */
  259.         ufreestr(old_data);
  260.  
  261.         es->es_len = new_len;   /* set new len */
  262.         ok = TRUE;
  263.     }
  264.     return (ok);
  265. }
  266.  
  267. BOOL ugly_dbg_set_estr(EXPSTR * es, CONSTRPTR s, STRPTR file, ULONG line)
  268. {
  269.     BOOL ok = FALSE;
  270.  
  271.     if (!es)
  272.         es_null("set_estr_mem", file, line);
  273.     else if (!s)
  274.         s_null("set_estr_mem", file, line);
  275.     else
  276.     {
  277.         size_t new_len = strlen(s) + 1;
  278.         STRPTR old_data = es->es_data;
  279.  
  280. #if DEBUG_UGLY_EXPSTR == 2
  281.         uglymem_wallcheck("setestr()", file, line);
  282. #endif
  283.  
  284.         if ((es->es_size == es->es_step)
  285.             && (es->es_size > new_len))
  286.         {
  287.  
  288.             strcpy(es->es_data, s);     /* copy new data */
  289.             es->es_len = new_len;       /* set new len */
  290.             ok = TRUE;
  291.  
  292.         }
  293.         else if (ugly_dbg_set_estr_mem(es, modadj(new_len, es->es_step), file, line))
  294.         {
  295.  
  296.             strcpy(es->es_data, s);     /* copy new & release old data */
  297.             ufree(old_data);
  298.  
  299.             es->es_len = new_len;       /* set new len */
  300.             ok = TRUE;
  301.         }
  302. #if DEBUG_UGLY_EXPSTR == 2
  303.         uglymem_wallcheck("setestr()", file, line);
  304. #endif
  305.  
  306.     }
  307.  
  308.     return (ok);
  309. }
  310.  
  311. /****** ugly.lib/clr_estr() **************************************************
  312. *
  313. *   NAME
  314. *       clr_estr -- clear data of an expandable string.
  315. *
  316. *   SYNOPSIS
  317. *       ok = clr_estr( string )
  318. *
  319. *       BOOL clr_estr
  320. *            ( EXPSTR * string )
  321. *
  322. *   FUNCTION
  323. *       Reset data of an expandable string to an empty string (""). This
  324. *       will reset the amount of memory to be used by this string to the
  325. *       initial size passed with init_estr().
  326. *
  327. *   INPUTS
  328. *       string - string to clear
  329. *
  330. *   RESULT
  331. *       ok - TRUE, if string could be cleared. If there have not been enough
  332. *            resources available to allocate a new buffer for the empty
  333. *            string, it will still contain the old data, and FALSE will be
  334. *            returned.
  335. *
  336. *   EXAMPLE
  337. *       ok = clr_estr( sepp );
  338. *
  339. *   SEE ALSO
  340. *       init_estr(), set_estr()
  341. *
  342. ******************************************************************************
  343. */
  344. BOOL ugly_clr_estr(EXPSTR * es)
  345. {
  346.     return (set_estr(es, ""));
  347. }
  348.  
  349. BOOL ugly_dbg_clr_estr(EXPSTR * es, STRPTR file, ULONG line)
  350. {
  351. #if DEBUG_UGLY_EXPSTR == 2
  352.     STRPTR s = es->es_data;
  353.     if (!s)
  354.         s = "<null>";
  355.     fprintf(stderr, DEXP "clr_estr(%p,`%s')\n", es, s);
  356.     uglymem_wallcheck("clr_estr()", file, line);
  357. #endif
  358.     return (ugly_dbg_set_estr(es, "", file, line));
  359. }
  360.  
  361. /*
  362.  * set_estrn
  363.  *
  364.  * set expstr with first n chars of string
  365.  */
  366. BOOL set_estrn(EXPSTR * es, CONSTRPTR s, size_t n)
  367. {
  368.     BOOL ok = FALSE;
  369.     STRPTR s1 = NULL;
  370.     size_t len = strlen(s);
  371.  
  372.     if (n > len)
  373.         n = len;
  374.  
  375.     s1 = (STRPTR) umalloc(n + 1);
  376.     if (s1)
  377.     {
  378.  
  379.         memcpy(s1, s, n);
  380.         s1[n] = 0;
  381.         ok = set_estr(es, s1);
  382.         ufree(s1);
  383.  
  384.     }
  385.     return (ok);
  386. }
  387.  
  388. /*
  389.  *-------------------------------------
  390.  * constructor / destructor
  391.  *-------------------------------------
  392.  */
  393.  
  394. /****** ugly.lib/init_estr() *************************************************
  395. *
  396. *   NAME
  397. *       init_estr -- create a new expandable string.
  398. *
  399. *   SYNOPSIS
  400. *       new_string = init_estr( initial_size )
  401. *
  402. *       EXPSTR * init_estr
  403. *            ( size_t initial_size )
  404. *
  405. *   FUNCTION
  406. *       Creates a new expandable string. Initialises the data that it
  407. *       represents an empty string.
  408. *
  409. *   INPUTS
  410. *       initial_size -
  411. *           Initial size to use for the string. This amount of memory
  412. *           will immdediately be allocated and is used to store the
  413. *           string data. If the string grows and data will not fit in
  414. *           this memory area any more, new memory will be allocated
  415. *
  416. *           If a value of `0' is used, a reasonable value will be
  417. *           used. This usualy depend on your OS, but will not be
  418. *           smaller than 8.
  419. *
  420. *   RESULT
  421. *       new_string - pointer to new string, or NULL if not enough
  422. *                    memory available
  423. *
  424. *   EXAMPLE
  425. *       EXPSTR * sepp = init_estr( 20 );
  426. *
  427. *   SEE ALSO
  428. *       del_estr(), clr_estr(), set_estr()
  429. *
  430. ******************************************************************************
  431. */
  432.  
  433. EXPSTR *ugly_dbg_init_estr(size_t step_size, STRPTR file, ULONG line)
  434. {
  435.     EXPSTR *es = ugly_malloc_tracking(sizeof(EXPSTR), file, line);
  436.  
  437.     if (es)
  438.     {
  439.  
  440.         if (step_size < ES_MIN_MEMSTEP)
  441.             step_size = ES_MIN_MEMSTEP;
  442.         es->es_data = NULL;
  443.         es->es_size = 0;
  444.         es->es_step = step_size;
  445.         if (!clr_estr(es))
  446.         {
  447.  
  448.             ufree(es);
  449.             es = NULL;
  450.  
  451.         }
  452.     }
  453.     return (es);
  454.  
  455. }
  456.  
  457. EXPSTR *ugly_init_estr(size_t step_size)
  458. {
  459.     EXPSTR *es = umalloc(sizeof(EXPSTR));
  460.  
  461.     if (es)
  462.     {
  463.  
  464.         if (step_size < ES_MIN_MEMSTEP)
  465.             step_size = ES_MIN_MEMSTEP;
  466.         es->es_data = NULL;
  467.         es->es_size = 0;
  468.         es->es_step = step_size;
  469.         if (!clr_estr(es))
  470.         {
  471.  
  472.             ufree(es);
  473.             es = NULL;
  474.  
  475.         }
  476.     }
  477.     return (es);
  478.  
  479. }
  480.  
  481. /****** ugly.lib/del_estr() **************************************************
  482. *
  483. *   NAME
  484. *       del_estr -- release all resources used by an expandable string
  485. *
  486. *   SYNOPSIS
  487. *       del_estr( string )
  488. *
  489. *       VOID * init_estr
  490. *            ( EXPSTR * string )
  491. *
  492. *   FUNCTION
  493. *       Releases all resources allocated by an expandable string. The data
  494. *       are no more valid afterwards and must not be accessed any more.
  495. *
  496. *   INPUTS
  497. *       string - expandable string to remove
  498. *
  499. *   EXAMPLE
  500. *       del_estr( sepp );
  501. *
  502. *   SEE ALSO
  503. *       init_estr()
  504. *
  505. ******************************************************************************
  506. */
  507. VOID del_estr(EXPSTR * es)
  508. {
  509. #if DEBUG_UGLY_EXPSTR
  510.     if (es)
  511.     {
  512.         if (es->es_data)
  513.         {
  514. #if DEBUG_UGLY_EXPSTR == 2
  515.             STRARR s[17];
  516.             strncpy(s, es->es_data, 17);
  517.             s[16] = 0;
  518.             D(fprintf(stderr, DEXP "del_estr(%p,`%s')\n", es, s));
  519.             umem_wallcheck("del_estr()");
  520. #endif
  521.         }
  522.         else
  523.         {
  524.             D(fprintf(stderr, DEXP "attempt to free null-data-estr\n"));
  525.         }
  526.     }
  527.     else
  528.     {
  529. #if DEBUG_UGLY_EXPSTR == 2
  530.         D(fprintf(stderr, DEXP "attempt to free null-estr\n"));
  531. #endif
  532.     }
  533. #endif
  534.  
  535.     if (es)
  536.     {
  537.  
  538.         ufree(es->es_data);
  539.         es->es_len = 0;
  540.         es->es_size = 0;
  541.         es->es_step = 0;
  542.         ufree(es);
  543.  
  544.     }
  545. }
  546.  
  547. /****** ugly.lib/app_estrch() **************************************************
  548. *
  549. *   NAME
  550. *       app_estrch -- append single character to an expandable string.
  551. *
  552. *   SYNOPSIS
  553. *       ok = app_estrch( string, ch )
  554. *
  555. *       BOOL app_estrch
  556. *            ( EXPSTR * string, int ch )
  557. *
  558. *   FUNCTION
  559. *       At the end of a string, a single character will be appended.
  560. *
  561. *   INPUTS
  562. *       string - string to which data should be appended
  563. *       ch     - character to append
  564. *
  565. *   RESULT
  566. *       ok - TRUE, if string could be updated. If there have not been enough
  567. *            resources available to allocate a new buffer for the new data,
  568. *            it will still contain the old data, and FALSE will be returned.
  569. *
  570. *   EXAMPLE
  571. *       ok = app_estrch( sepp, 'x' );
  572. *
  573. *   BUGS
  574. *       Result is undefined, if (ch > 255) or (ch < 0).
  575. *
  576. *   SEE ALSO
  577. *       app_estr()
  578. *
  579. ******************************************************************************
  580. */
  581. BOOL ugly_app_estrch(EXPSTR * es, int ch)
  582. {
  583.     BOOL ok = TRUE;
  584.  
  585.     if (es->es_len >= es->es_size)
  586.     {                           /* enough mem left? */
  587.  
  588.         STRPTR old_data = es->es_data;  /* N->remeber old data ptr */
  589.  
  590.         if (set_estr_mem(es,
  591.                          es->es_size + es->es_step))
  592.         {                       /*    set new mem sucessful? */
  593.  
  594.             strcpy(es->es_data, /*    Y->copy old data */
  595.                    old_data);
  596.             ufree(old_data);    /*       release old data */
  597.  
  598.         }
  599.         else
  600.         {
  601.             /*    N->return error */
  602.             ok = FALSE;
  603.         }
  604.     }
  605.     if (ok)
  606.     {
  607.  
  608.         STRPTR s;
  609.         s = es->es_data;
  610.         s[es->es_len - 1] = ch; /* append new char to expstr */
  611.         s[es->es_len] = 0;
  612.         es->es_len++;           /* incr. expstr length */
  613.  
  614.     }
  615.     return (ok);
  616. }
  617.  
  618. BOOL ugly_dbg_app_estrch(EXPSTR * es, int ch, STRPTR file, ULONG line)
  619. {
  620.     BOOL ok = TRUE;
  621.  
  622.     if (!es)
  623.     {
  624.         es_null("app_estrch", file, line);
  625.         ok = FALSE;
  626.     }
  627.     else if (es->es_len >= es->es_size)
  628.     {                           /* enough mem left? */
  629.  
  630.         STRPTR old_data = es->es_data;  /* N->remeber old data ptr */
  631.  
  632.         if (ugly_dbg_set_estr_mem(es,
  633.                                   es->es_size + es->es_step, file, line))
  634.         {
  635.             /*    set new mem sucessfully? */
  636.  
  637.             strcpy(es->es_data, /*    Y->copy old data */
  638.                    old_data);
  639.             ufree(old_data);    /*       release old data */
  640.         }
  641.         else
  642.         {                       /*    N->return error */
  643.             ok = FALSE;
  644.         }
  645.     }
  646.     if (ok)
  647.     {
  648.  
  649.         STRPTR s;
  650.         s = es->es_data;
  651.         s[es->es_len - 1] = ch; /* append new char to expstr */
  652.         s[es->es_len] = 0;
  653.         es->es_len++;           /* incr. expstr length */
  654.  
  655.     }
  656.     return (ok);
  657. }
  658.  
  659. /****** ugly.lib/app_estr() **************************************************
  660. *
  661. *   NAME
  662. *       app_estr -- append data to an expandable string.
  663. *
  664. *   SYNOPSIS
  665. *       ok = app_estr( string, data )
  666. *
  667. *       BOOL app_estr
  668. *            ( EXPSTR * string, STRPTR data )
  669. *
  670. *   FUNCTION
  671. *       At the end of a string, new data will be appended.
  672. *
  673. *   INPUTS
  674. *       string - string to which data should be appended
  675. *       data   - new data to append, represented as a normal zero-terminated
  676. *                C-string
  677. *
  678. *   RESULT
  679. *       ok - TRUE, if string could be updated. If there have not been enough
  680. *            resources available to allocate a new buffer for the new data,
  681. *            it will still contain the old data, and FALSE will be returned.
  682. *
  683. *   EXAMPLE
  684. *       ok = app_estr( sepp, "data to append" );
  685. *
  686. *   SEE ALSO
  687. *       estrcat(), set_estr(), estrcpy()
  688. *
  689. ******************************************************************************
  690. */
  691. BOOL ugly_app_estr(EXPSTR * es, CONSTRPTR s)
  692. {
  693.     BOOL ok = TRUE;
  694.     size_t slen = strlen(s);
  695.  
  696.     ok = TRUE;
  697.     if ((es->es_len + slen - 1) >= es->es_size)
  698.     {                           /* enough mem left? */
  699.  
  700.         STRPTR old_data = es->es_data;  /* N->remeber old data ptr */
  701.  
  702.         if (ugly_set_estr_mem(es,
  703.                               modadj(es->es_len + slen + 1, es->es_step)))
  704.         {
  705.             /*    set new mem sucessful? */
  706.             strcpy(es->es_data, /*    Y->copy old data */
  707.                    old_data);
  708.             ufree(old_data);    /*       release old data */
  709.         }
  710.         else
  711.         {                       /*    N->return error */
  712.             ok = FALSE;
  713.         }
  714.     }
  715.     if (ok)
  716.     {
  717.  
  718.         STRPTR ds;
  719.         ds = es->es_data + (es->es_len - 1);
  720.         strcat(ds, s);
  721.         /* append new char to expstr */
  722.         es->es_len += slen;     /* incr. expstr length */
  723.         es->es_data[es->es_len - 1] = 0;
  724.  
  725.     }
  726.     return (ok);
  727. }
  728.  
  729. BOOL ugly_dbg_app_estr(EXPSTR * es, CONSTRPTR s, STRPTR file, ULONG line)
  730. {
  731.     BOOL ok = FALSE;
  732.  
  733.     if (!es)
  734.         es_null("app_estr", file, line);
  735.     else if (!s)
  736.         s_null("app_estr", file, line);
  737.     else
  738.     {
  739.         /* faster, but maybe buggy */
  740.         size_t slen = strlen(s);
  741.  
  742.         ok = TRUE;
  743.         if ((es->es_len + slen - 1) >= es->es_size)
  744.         {                       /* enough mem left? */
  745.  
  746.             STRPTR old_data = es->es_data;      /* N->remeber old data ptr */
  747.  
  748.             if (ugly_dbg_set_estr_mem(es,
  749.                     modadj(es->es_len + slen + 1, es->es_step), file, line))
  750.             {                   /*    set new mem sucessful? */
  751.  
  752.                 strcpy(es->es_data,     /*    Y->copy old data */
  753.                        old_data);
  754.                 ufree(old_data);        /*       release old data */
  755.             }
  756.             else
  757.             {                   /*    N->return error */
  758.                 ok = FALSE;
  759.             }
  760.         }
  761.         if (ok)
  762.         {
  763.  
  764.             STRPTR ds;
  765.             ds = es->es_data + (es->es_len - 1);
  766.             strcat(ds, s);
  767.             /* append new char to expstr */
  768.             es->es_len += slen; /* incr. expstr length */
  769.             es->es_data[es->es_len - 1] = 0;
  770.  
  771.         }
  772.     }
  773.  
  774.     return (ok);
  775. }
  776.  
  777. /*
  778.  *-------------------------------------
  779.  * get part of expstr
  780.  *-------------------------------------
  781.  */
  782.  
  783. /*
  784.  * todo: handle special cases like
  785.  * get_right_estr( .., "hugo", 99 );
  786.  */
  787.  
  788. /*
  789.  * get_mid_estr
  790.  *
  791.  * get a part from a expstr; compare BASIC's "MID$()"
  792.  *
  793.  * params: dest...destination expstr where to store result part
  794.  *         src....source expstr where to get part from
  795.  *         from...position of char where to begin part (0=first char)
  796.  *         num....number of chars to get
  797.  * result: TRUE and result in dest if ok; else FALSE is returned an
  798.  *         dest is left untouched
  799.  *
  800.  * NOTE: it is possible to use the source-exstr as destination-expstr,
  801.  *       because the result is copied to a temp. expstr before
  802.  *       ( example: get_mid_estr( hugo, hugo, 3, 4 ); )
  803.  */
  804. BOOL get_mid_estr(EXPSTR * dest, EXPSTR * src, size_t from, size_t num)
  805. {
  806.     BOOL ok = FALSE;
  807.     EXPSTR *tmp = init_estr(dest->es_step);
  808.  
  809.     if (tmp)
  810.     {
  811.  
  812.         STRPTR old_data = tmp->es_data;
  813.  
  814.         /* check size */
  815.         if (from >= src->es_len)
  816.             from = src->es_len - 1;
  817.         if (from + num >= src->es_len)
  818.             num = src->es_len - from - 1;
  819.  
  820.         /* set new mem for tmp */
  821.         ok = set_estr_mem(tmp, modadj(num + 1, tmp->es_step));
  822.  
  823.         if (ok)
  824.         {
  825.  
  826.             /* copy data */
  827.             strncpy(estr2str(tmp), estr2str(src) + from, num);
  828.             tmp->es_data[num] = 0;
  829.             tmp->es_len = num + 1;
  830.             ufree(old_data);
  831.  
  832.             ok = estrcpy(dest, tmp);
  833.  
  834.         }
  835.         del_estr(tmp);
  836.  
  837.     }
  838.     return (ok);
  839. }
  840.  
  841. /*
  842.  * get_right_estr
  843.  *
  844.  * get right part from a expstr; compare BASIC's "RIGHT$()"
  845.  */
  846. BOOL get_right_estr(EXPSTR * dest, EXPSTR * src, size_t num)
  847. {
  848.     if (num >= src->es_len)
  849.         num = src->es_len - 1;
  850.  
  851.     return (get_mid_estr(dest, src, (src->es_len - num - 1), num));
  852. }
  853.  
  854. /*
  855.  * get_left_estr
  856.  *
  857.  * get left part from a expstr; compare BASIC's "LEFT$()"
  858.  */
  859. BOOL get_left_estr(EXPSTR * dest, EXPSTR * src, size_t num)
  860. {
  861.     return (get_mid_estr(dest, src, 0, num));
  862. }
  863.  
  864. /*
  865.  *-------------------------------------
  866.  * misc. functions
  867.  *-------------------------------------
  868.  */
  869.  
  870. /****** ugly.lib/estr2str() *************************************************
  871. *
  872. *   NAME
  873. *       estr2str -- convert expandable string to standard string
  874. *
  875. *   SYNOPSIS
  876. *       s = estr2str( string )
  877. *
  878. *       STRPTR estr2str
  879. *            ( EXPSTR * string )
  880. *
  881. *   FUNCTION
  882. *       Copy data from a source string (old) to a destination string (new).
  883. *
  884. *   INPUTS
  885. *       string - expandable string to convert; if you pass NULL, this
  886. *                function crashes.
  887. *
  888. *   RESULT
  889. *       s - pointer to data of string, terminated with a zero-character
  890. *           ('\0')
  891. *
  892. *   EXAMPLE
  893. *       EXPSTR * hugo = init_estr(0);
  894. *       STRPTR data;
  895. *       ...
  896. *       data = estr2str( hugo );
  897. *
  898. *   SEE ALSO
  899. *       set_estr(), estrlen()
  900. *
  901. ******************************************************************************
  902. */
  903. STRPTR ugly_estr2str(EXPSTR * es)
  904. {
  905.     return (es->es_data);
  906. }
  907.  
  908. /****** ugly.lib/estrlen() *************************************************
  909. *
  910. *   NAME
  911. *       estrlen -- dtermines length of an expandable string
  912. *
  913. *   SYNOPSIS
  914. *       len = estrlen( string )
  915. *
  916. *       size_t estrlen
  917. *            ( EXPSTR * string )
  918. *
  919. *   FUNCTION
  920. *       This functions determines the number of characters stored in an
  921. *       expandable string.
  922. *
  923. *   INPUTS
  924. *       string - expandable string to examine; if you pass NULL, this
  925. *                function crashes.
  926. *
  927. *   RESULT
  928. *       len - length of string
  929. *
  930. *   EXAMPLE
  931. *       EXPSTR * hugo = init_estr(0);
  932. *       size_t len;
  933. *       ...
  934. *       len = estrlen( hugo );
  935. *
  936. *   NOTES
  937. *       As expandable strings always keep track of their current length,
  938. *       this functions always executes in O(1) versus classic strlen(),
  939. *       which always has to examine the whole string and therefor always
  940. *       executes in O(n), with n = number of characters stored.
  941. *
  942. *   SEE ALSO
  943. *       estr2str()
  944. *
  945. ******************************************************************************
  946. */
  947. size_t ugly_estrlen(EXPSTR * es)
  948. {
  949.     return (es->es_len - 1);
  950. }
  951.  
  952. /****** ugly.lib/estrcpy() **************************************************
  953. *
  954. *   NAME
  955. *       estrcpy -- copy data of an expandable string
  956. *
  957. *   SYNOPSIS
  958. *       ok = estrcpy( new, old )
  959. *
  960. *       BOOL estrcpy
  961. *            ( EXPSTR * new, EXPPTR * old )
  962. *
  963. *   FUNCTION
  964. *       Copy data from a source string (old) to a destination string (new).
  965. *
  966. *   INPUTS
  967. *       new - destination string
  968. *       old - source string
  969. *
  970. *   RESULT
  971. *       ok - TRUE, if string could be updated. If there have not been enough
  972. *            resources available to allocate a new buffer for the new data,
  973. *            it will still contain the old data, and FALSE will be returned.
  974. *
  975. *   EXAMPLE
  976. *       EXPSTR * hugo = init_estr(0);
  977. *       EXPSTR * sepp = init_estr(0);
  978. *       BOOL ok;
  979. *       ...
  980. *       ok = estrcpy( sepp, hugo );
  981. *
  982. *   SEE ALSO
  983. *       estrcat(), set_estr()
  984. *
  985. ******************************************************************************
  986. */
  987. BOOL estrcpy(EXPSTR * dest, EXPSTR * src)
  988. {
  989.     return (set_estr(dest, estr2str(src)));
  990. }
  991.  
  992. /****** ugly.lib/estrcat() **************************************************
  993. *
  994. *   NAME
  995. *       estrcat -- concatenate two expandable strings
  996. *
  997. *   SYNOPSIS
  998. *       ok = estrcat( dest, app )
  999. *
  1000. *       BOOL estrcat
  1001. *            ( EXPSTR * dest, EXPPTR * app )
  1002. *
  1003. *   FUNCTION
  1004. *       Append data of an string to another one and store the result in it.
  1005. *
  1006. *   INPUTS
  1007. *       dest -
  1008. *       app -
  1009. *
  1010. *   RESULT
  1011. *       ok - TRUE, if string could be updated. If there have not been enough
  1012. *            resources available to allocate a new buffer for the new data,
  1013. *            it will still contain the old data, and FALSE will be returned.
  1014. *
  1015. *   EXAMPLE
  1016. *       EXPSTR * hugo = init_estr(0);
  1017. *       EXPSTR * sepp = init_estr(0);
  1018. *       BOOL ok;
  1019. *       ...
  1020. *       ok = estrcat( sepp, hugo );
  1021. *
  1022. *   SEE ALSO
  1023. *       app_estr(), estrcpy()
  1024. *
  1025. ******************************************************************************
  1026. */
  1027. BOOL estrcat(EXPSTR * dest, EXPSTR * src)
  1028. {
  1029.     return (app_estr(dest, estr2str(src)));
  1030. }
  1031.